#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include "NativeMath.h"

#ifndef _MSC_VER

char* itoa(int n, char *buff, int radix)
// convert a positive integer n to char *buff
// for instant, this function work with radix <= 10;
// a little change to run with radix > 10
{
     int q, r;
     int i = 0;
     char tmp[33];  // for radix = 2 and 32 bits computer
     do {
          q = (int)(n / radix);
          r = n % radix;
          n = q;
          tmp[i++] = 48 + r;
     } while(q > 0);
     int j;
     for(j = 0; j < i; j++){
          buff[j] = tmp[i - j - 1];
     }
     buff[j] = NULL;
     return buff;
}
#endif

/*
* Print the binary string representation of the integer
* to the buffer.
*/
EXPORT void tobinstr(const ninteger* value, const char* buffer, const size_t capacity) 
{
	int i;

	/* check if buffer is large enough */
	if(value->width > capacity)
	{
		perror("insufficient capacity");
	}

	for(i = value->width - 1; i >= 0; i--) 
	{
		if(getbit(value, i))
		{
			strcat(buffer, "1");
		} 
		else 
		{
			strcat(buffer, "0");
		}
	}
}

/*
* Inserts the prefix into the buffer with the specified capacity.
*/
static void prependstr(const char* prefix, const char* buffer, const size_t capacity)
{
	/* string lengths excluding ending null-terminator */
	const size_t slen = strlen(buffer);
	const size_t plen = strlen(prefix);

	const char* tmpbuf = (const char*)calloc(slen + plen + 1, sizeof(char));

	/* check that buffer is wide enough */
	assert(slen + plen + 1 < capacity);

	sprintf(tmpbuf, "%s%s", prefix,  buffer);
	strcpy(buffer, tmpbuf);

	free(tmpbuf);
}

/*
* Print the decimal string representation of the integer
* to the buffer.
*/
EXPORT void todecstr(const ninteger* value, const char* buffer, const size_t capacity) 
{
	char* c;
	UINT r = 0;

	/* make a copy of content */    
	uintarray* t = alloc_uintarr(value->content->length);
	assert(t != NULL); /* check if we're out of memory */
	memcpy(t->values, value->content->values, t->length * sizeof(UINT));


	if(value->issigned)
	{
		BOOL appendminus = FALSE;
		if (isnegative(value))
		{
			negateinternal(t, t);
			appendminus = TRUE;
		}

		do
		{
			divinternal2(&t, &r, t, 10u);
			c = itoa(r, buffer, 10);
			//prependstr(c, buffer, capacity);
		} while (!iszeroarr(t));

		if (appendminus)
			prependstr("-", buffer, capacity);
	}
	else /* integer is unsigned */
	{
		do
		{
			divinternal2(&t, &r, t, 10);
			c = itoa((int)r, buffer, 10);
			prependstr(c, buffer, capacity);
		} while (!iszeroarr(t));
	}

	/* cleanup */
	free_uintarr(t);
}

/*
* Print the hexadecimal string representation of the integer
* to the buffer.
*
* TODO: check that buffer capacity is not exeeded
*/
EXPORT void tohexstr(const ninteger* value, const char* buffer, const size_t capacity) 
{
	const char tmpbuf[20]; /* buffer to hold itoa output */
	int i = value->content->length - 1;
	UINT v;

	if(value->issigned && isnegative(value))
	{
		v = (value->width % BASE_TYPE_BITS == 0) ?
			value->content->values[i] :
		value->content->values[i] & bitmasks[value->width % BASE_TYPE_BITS];

		itoa(v, buffer, 16);
		i--;
	}
	else
	{
		while((value->content->values[i] == 0) && (i > 0))
			i--;

		itoa(value->content->values[i--], buffer, 16);
	}

	while(i >= 0)
	{
		sprintf(tmpbuf, "%08x", value->content->values[i--]);
		strcat(buffer, tmpbuf);
	}
}
